S3のPresigned URLで作るリンクでファイルダウンロードを強制する

S3のPresigned URLで作るリンクでファイルダウンロードを強制する

Amazon S3のPresigned URLで取得するファイルをブラウザでの表示を避け、ファイルダウンロードを強制したいケースがあったので、その方法を共有します。Content-Dispositionヘッダーを利用します。
Clock Icon2024.11.06

Amazon S3にはPresigned URL(署名付きURL)という機能があり、S3オブジェクトの限定的なアクセスを提供できます。
弊社ブログでもいくつかやり方が紹介されています。

このPresigned URLをブラウザで開くと、その挙動はブラウザ依存で変わります。
ファイルの種類によってはブラウザで直接表示されたり、ダウンロードされたりする場合があります。

今回、ブラウザでの表示を避け、ファイルダウンロードを強制したいケースがあったので、その方法を共有します。

Content-Dispositionヘッダー

結論から言うと、Content-Disposition ヘッダーを利用します。

Content-Disposition ヘッダーは、HTTPレスポンスヘッダーの1つで、ファイルのインライン表示やダウンロード時の挙動を制御するために使用します。

Presigned URLを生成する際に、レスポンスにこの Content-Disposition ヘッダーを設定できます。

Boto3を使った例

Pythonでboto3ライブラリを使ってPresigned URLを生成する例を紹介します。

Presigned URLを生成する際に、次の設定をしておくと、Presigned URLのアクセス時のレスポンスに Content-Disposition ヘッダーが設定されます。
そうすると、生成したPresigned URLをブラウザで開くと、ファイルがダウンロードされる挙動となります。

具体的には次のようなコードです。

# バケット名,オブジェクト名
BUCKET_NAME = '<<YOUR S3 BUCKET NAME>>'
OBJECT_KEY_NAME = '<<YOUR S3 OBJECT KEY NAME>>'

import boto3
from botocore.exceptions import NoCredentialsError

def generate_presigned_url(bucket_name, object_key, filename=None, expiration=3600):
    if filename is None:
        filename = object_key

    s3_client = boto3.client('s3')

    try:
        response = s3_client.generate_presigned_url(
            'get_object',
            Params={
                'Bucket': bucket_name,
                'Key': object_key,
                'ResponseContentDisposition': 'attachment; filename="{}"'.format(filename)
            },
            ExpiresIn=expiration)
    except NoCredentialsError:
        print("Credentials not available")
        return None

    return response

if __name__=='__main__':
    bucket_name = BUCKET_NAME
    object_key = OBJECT_KEY_NAME
    url = generate_presigned_url(bucket_name, object_key, 'sample.txt')
    print(f"Presigned URL: {url}")

パラメーターの深堀り

generate_presigned_url メソッドのパラメーターに何が使えるか、どのように考えれば良いでしょうか?
もう少し深堀りしてみます。

まずは、ドキュメントを見てみましょう。

正直、よくわからないですね。

この辺の記述と、Presigned URLの正体が AWS APIのリクエスト署名したURL であることから読み解いていきます。

Parameters:

  • ClientMethod (string) – The client method to presign for
  • Params (dict) – The parameters normally passed to ClientMethod.
  • ExpiresIn (int) – The number of seconds the presigned url is valid for. By default it expires in an hour (3600 seconds)
  • HttpMethod (string) – The http method to use on the generated url. By default, the http method is whatever is used in the method’s model.

おそらく generate_presigned_url メソッドの ClientMethod パラメーターは、 get_object 等メソッド名を文字列で受け取り、 Params パラメーターには、get_object メソッドのパラメーターがそのまま使えるのでしょう。

get_object メソッドのドキュメントを見ると、 ResponseContentDisposition というパラメーターがあり、これがレスポンスに Content-Disposition ヘッダーを設定するためのパラメーターであることがわかります。

この前提でサンプルプログラムのようにパラメーターを設定してPresigned URLを生成し、次のように curl コマンドでアクセスしてみると、 Content-Disposition ヘッダーが設定されていることが確認できます。

$ PRESIGNED_URL="<<YOUR PRESIGNED URL>>"
$ curl -D - ${PRESIGNED_URL}
HTTP/1.1 200 OK
x-amz-id-2: dr65zHDCXfVByWA4oMSf+msizvqCiQk/vA1wOYtf4N5tRbdhIJ83jq1EwLdleK0199SPvmrFjnU=
x-amz-request-id: RF8CH96SBZTHM7KM
Date: Wed, 06 Nov 2024 08:32:17 GMT
Last-Modified: Sun, 31 Jan 2021 12:52:39 GMT
ETag: "ab41eff9c43c9837a78093369a174315"
Content-Disposition: attachment; filename="sample.txt"
Accept-Ranges: bytes
Content-Type: application/json
Server: AmazonS3
Content-Length: 35

{
    "greeting": "Hello, World!"
}

なので、パラメーターの使い方はこの理解で合っていそうです。

おわりに

S3のPresigned URLでファイルダウンロードの強制を試してみました。

S3のPresigned URLで他にも制御できるレスポンスヘッダーがあるので、いろいろ活用できそうです。

例えば、 Content-Type ヘッダーを設定しておくことで、ファイルのMIMEタイプを指定できます。

レスポンスヘッダーで挙動を制御できることを知っておくと、S3のPresigned URLがより便利に使えそうです。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.